// Rust sokoban
// main.rs

use ggez::{conf, event::{self, KeyCode, KeyMods}, timer, Context, GameResult};
use specs::{RunNow, World, WorldExt};
use std::path;

//声明要引入的模块 xxx.rs 是一个mod，文件夹 也是一个mod
mod components;
mod constants;//引入常量 不需要 use xxx
mod entities;
mod map;
mod resources;
mod systems;//systems 文件夹 中的 mod.rs 中 pub use过了
mod events; //必须在main中 mod 声明 不然别的模块中使用的时候 也会报错
mod audio;

//具体引入模块的某些函数
use crate::components::*;
use crate::map::*;
use crate::resources::*;
use crate::systems::*;
use crate::audio::*;

struct Game {
    world: World,
}

impl event::EventHandler<ggez::GameError> for Game {
    fn update(&mut self, _context: &mut Context) -> GameResult {
        // Run input system
        {
            let mut is = InputSystem {};
            is.run_now(&self.world);
        }
        let mut gss = GameplayStateSystem {};
        gss.run_now(&self.world);

        let mut time = self.world.write_resource::<Time>();
        time.delta += timer::delta(_context);
        
        //声音 音效展示
        let mut es = EventSystem { context:_context };//对于传入参数==obj 属性的，直接写  EventSystem { context}即可，否则需要写{a:b}  给属性赋值 
        es.run_now(&self.world);

        Ok(())
    }

    fn draw(&mut self, context: &mut Context) -> GameResult {
        // Render game entities 渲染世界
        {
            let mut rs = RenderingSystem { context };
            rs.run_now(&self.world);
        }

        Ok(())
    }

    fn key_down_event(
        &mut self,
        _context: &mut Context,
        keycode: KeyCode,
        _keymod: KeyMods,
        _repeat: bool,
    ) {
        println!("Key pressed: {:?}", keycode);

        let mut input_queue = self.world.write_resource::<InputQueue>();
        input_queue.keys_pressed.push(keycode);
    }
}

// Initialize the level
pub fn initialize_level(world: &mut World) {
    const MAP: &str = "
    N N W W W W W W
    W W W . . . . W
    W . . . BB . . W
    W . . RB . . . W 
    W . P . . . . W
    W . . . . RS . W
    W . . BS . . . W
    W . . . . . . W
    W W W W W W W W
    ";

    load_map(world, MAP.to_string());
}

pub fn main() -> GameResult {
    let mut world = World::new();
    register_components(&mut world);
    register_resources(&mut world);
    initialize_level(&mut world);

    // Create a game context and event loop
    let context_builder = ggez::ContextBuilder::new("rust_sokoban", "sokoban")
        .window_setup(conf::WindowSetup::default().title("Rust Sokoban!"))
        .window_mode(conf::WindowMode::default().dimensions(800.0, 600.0))
        .add_resource_path(path::PathBuf::from("./resources"));

    let (mut context, event_loop) = context_builder.build()?;
    initialize_sounds(&mut world, &mut context);
    // Create the game state
    let game = Game { world };
    // Run the main event loop
    event::run(context, event_loop, game)
}
